
#include <material_editor/effecteditor.h>
#include <material_editor/selectmaterialdatadialog.h>
#include <materialdatalistmodel.h>
#include <session.h>

class EffectStagesModel : public QAbstractItemModel
{
private:
	Effect* _effect;

public:
	EffectStagesModel () : QAbstractItemModel (), _effect (0)
	{
	}

	void StageAdded ()
	{
		reset ();
	}

	void SetEffect (Effect* effect)
	{
		_effect = effect;
		reset ();
	}

	int columnCount (const QModelIndex &parent = QModelIndex()) const { return 1; }
	QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const
	{
		if (role != Qt::DisplayRole || !index.isValid ())
			{
				return QVariant ();
			}
		QString text = QString ("Stage %1").arg (index.row () + 1);
		return QVariant (text);
	}

	QModelIndex index (int row, int column, const QModelIndex &parent = QModelIndex()) const
	{
		if (parent.isValid () || column != 0 || !_effect || row >= _effect->GetNumberOfStages ())
		{
			return QModelIndex ();
		}
		
		return createIndex (row, column);
	}

	QModelIndex parent (const QModelIndex &index) const
	{
		return QModelIndex ();
	}

	int rowCount (const QModelIndex &parent = QModelIndex()) const
	{
		if (parent.isValid () || !_effect) return 0;
		return _effect->GetNumberOfStages ();
	}

};


class EffectProgramsModel : public QAbstractItemModel
{
private:
	Effect* _effect;
	unsigned _stage;
public:
	EffectProgramsModel () : QAbstractItemModel (), _effect (0)
	{
	}

	void SetStage (unsigned stage)
	{
		_stage = stage;
		reset ();
	}

	unsigned GetStage ()
	{
		return _stage;
	}

	const QString& GetPassName (unsigned row)
	{
		return _effect->GetProgramName (_stage, row);
	}


	void SetEffect (Effect* effect)
	{
		_effect = effect;
		SetStage(0);
	}

	int columnCount (const QModelIndex &parent = QModelIndex()) const 
	{ 
		if (parent.isValid ()) return 0;
		return 2; 
	}

	QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const
	{
		if (role != Qt::DisplayRole) return QVariant ();
		switch (section)
			{
			case 0:
				return QVariant ("Pass");
			case 1:
				return QVariant ("Program");
			}
		return QVariant ();
	}


	QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const
	{
		if (role != Qt::DisplayRole || !index.isValid () || !_effect || index.column () >= 2)
			{
				return QVariant ();
			}

		unsigned num = _effect->GetNumberOfPrograms (_stage);
		if (index.row () >= num)
			{
				return QVariant ();
			}

		if (index.column () == 0)
			{
				return QVariant (_effect->GetProgramName (_stage, index.row ()));
			}
		else if (index.column () == 1)
			{
				Program* prog = _effect->GetProgram (_stage, _effect->GetProgramName (_stage, index.row ()));
				if (prog)
					{
						return QVariant (prog->GetCategory().GetFullName()+"."+prog->GetFullname());
					}
			
				return  QVariant ("<undefined>");
			}
		return QVariant ();
	}

	QModelIndex index (int row, int column, const QModelIndex &parent = QModelIndex()) const
	{
		if (parent.isValid () || column >= 2 || !_effect || row >= _effect->GetNumberOfPrograms (_stage))
		{
			return QModelIndex ();
		}
		
		return createIndex (row, column);
	}

	QModelIndex parent (const QModelIndex &index) const
	{
		return QModelIndex ();
	}

	int rowCount (const QModelIndex &parent = QModelIndex()) const
	{
		if (parent.isValid () || !_effect) return 0;
		return _effect->GetNumberOfPrograms(_stage);
	}

};


EffectEditor::EffectEditor(Effect* effect, MaterialView* view, QWidget *parent)
  : BaseMaterialEditorWidget(parent)
  , _materialView(view)
  , _effect (0)
{
  _gui.setupUi(this);
  _groupView = new GroupTreeItemView(this);
  QGridLayout* layout = new QGridLayout(_gui.widgetCategory);
  layout->setContentsMargins(QMargins (0, 0, 0, 0));
  layout->addWidget (_groupView, 0, 0);


	_stagesModel = new EffectStagesModel ();
	_gui.listViewStages->setModel (_stagesModel);

	_programsModel = new EffectProgramsModel ();
	_gui.treeViewPrograms->setModel (_programsModel);

	_gui.pushButtonAddStage->setEnabled (false);
	_gui.pushButtonRemoveStage->setEnabled (false);
  if (effect)
    {
      SetEffect(effect);
    }
}

void EffectEditor::SetEffect(Effect *effect)
{
  _effect = effect;

	_stagesModel->SetEffect (effect);
	_programsModel->SetEffect (effect);
	_programsModel->SetStage (0);

	_gui.pushButtonAddStage->setEnabled (effect != 0);
  _groupView->SetGroupTreeItem(&effect->GetCategory());

  SetItem (effect);

	SetDirty (false);
}

void EffectEditor::on_pushButtonAddStage_clicked ()
{
	if (!_effect)
		{
			return;
		}

	_effect->AddStage ();
	_stagesModel->StageAdded ();
	SetDirty(true);
}

void EffectEditor::on_pushButtonRemoveStage_clicked ()
{
	if (!_effect)
		{
			return;
		}
	QModelIndex index = _gui.listViewStages->currentIndex ();
	if (!index.isValid ())
		{
			_gui.pushButtonRemoveStage->setEnabled (false);
		}

	_effect->RemoveStage (index.row ());
	_stagesModel->SetEffect (_effect);
	_programsModel->SetStage (0);
}

void EffectEditor::on_treeViewPrograms_activated (const QModelIndex& index)
{
	if (!index.isValid ())
		{
			return;
		}
	unsigned stage = _programsModel->GetStage ();
	const QString& name = _programsModel->GetPassName (index.row());

	Program* prog = _effect->GetProgram (stage, name);
	Program* prog1 = GetProgram (prog);
	if (prog1 != prog)
		{
			SetDirty (true);
		}
	_effect->SetProgram (stage, name, prog1);
	_programsModel->SetStage(stage);
}

void EffectEditor::on_listViewStages_clicked (const QModelIndex& index)
{
	_gui.pushButtonRemoveStage->setEnabled (index.isValid ());

	_programsModel->SetStage (index.row ());
}




Program* EffectEditor::GetProgram(Program *current)
{
  SelectMaterialDataDialog dlg (Session::Get()->GetMainWindow());
  AllProgramDelegator delegator (Session::Get()->GetMaterialManager());
  dlg.SetDelegator(&delegator);
	dlg.SetClearButtonVisible (true);
  if (dlg.exec() != QDialog::Accepted)
    {
      return current;
    }
  return static_cast<Program*>(dlg.GetData ());
}

void EffectEditor::Save()
{
  if (!_effect) return;


  _effect->Save();
  SetDirty(false);
}
